package com.anlogic.sdk.openocd.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.logging.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;

import com.anlogic.sdk.openocd.model.JtagCable;
import com.anlogic.sdk.openocd.model.JtagDevice;
import com.anlogic.sdk.utils.LogUtils;
import com.anlogic.sdk.utils.ProcLauncherUtils;
import com.anlogic.sdk.utils.UIUtils;

public class OpenocdUtils {
	private static Logger logger = LogUtils.getLogger(OpenocdUtils.class);
	
	private static final String START_SCAN_PORT = "start scan port";
	private static final String CABLE_BASE_NAME = "JTAG Cable";
	
	private static final Pattern JTAG_SPEED_PATTERN =  Pattern.compile("Info : clock speed (\\w+) kHz");
	private static final Pattern JTAG_PORT_PATTERN =  Pattern.compile(START_SCAN_PORT + " (.*)");
	private static final Pattern JTAG_DEVICE_PATTERN = Pattern.compile(".*\"jtag newtap (\\w+) tap -irlen (\\w+) -expected-id (\\w+)\"");
	
	public static List<JtagCable> scanUsb(String vid, String pid) {
		String scanResult = ProcLauncherUtils.scanUsb(vid, pid);
		
		List<JtagCable> jtagCableDevices = new ArrayList<JtagCable>();
		
		String cableName = "";
		JtagCable cable = null;
		String[] lines = scanResult.split("\n");
		
		for (String line : lines) {
			if (line.startsWith(START_SCAN_PORT)) {
				cableName = CABLE_BASE_NAME;
				cable = new JtagCable();
				cable.setName(cableName);
				jtagCableDevices.add(cable);
			}
			
			if (cable == null) {
				continue;
			}
			
			Matcher portMatcher = JTAG_PORT_PATTERN.matcher(line);
			Matcher speedMatcher = JTAG_SPEED_PATTERN.matcher(line);
			Matcher deviceMatcher = JTAG_DEVICE_PATTERN.matcher(line);
			
			if (portMatcher.find()) {
				cableName = String.format("%s (%s)", cableName, portMatcher.group(1));
				cable.setName(cableName);
				cable.setUsbPort(portMatcher.group(1));
			}
			
			if (speedMatcher.find()) {
				cable.setFrequency(speedMatcher.group(1));
			}
			
			if (deviceMatcher.find()) {
				JtagDevice device = new JtagDevice(deviceMatcher.group(1), deviceMatcher.group(3), deviceMatcher.group(2), false);
				cable.addDevice(device);
			}
		}
		
		return jtagCableDevices;
	}
	
	public static List<JtagCable> parseUsbScanResult(String scanResult) {
		List<JtagCable> jtagCableDevices = new ArrayList<JtagCable>();
		
		String cableName = "";
		JtagCable cable = null;
		String[] lines = scanResult.split("\n");
		
		for (String line : lines) {
			if (line.startsWith(START_SCAN_PORT)) {
				cableName = CABLE_BASE_NAME;
				cable = new JtagCable();
				cable.setName(cableName);
				jtagCableDevices.add(cable);
			}
			
			if (cable == null) {
				continue;
			}
			
			Matcher portMatcher = JTAG_PORT_PATTERN.matcher(line);
			Matcher speedMatcher = JTAG_SPEED_PATTERN.matcher(line);
			Matcher deviceMatcher = JTAG_DEVICE_PATTERN.matcher(line);
			
			if (portMatcher.find()) {
				cableName = String.format("%s (%s)", cableName, portMatcher.group(1));
				cable.setName(cableName);
				cable.setUsbPort(portMatcher.group(1));
			}
			
			if (speedMatcher.find()) {
				cable.setFrequency(speedMatcher.group(1));
			}
			
			if (deviceMatcher.find()) {
				if (Integer.parseInt(deviceMatcher.group(3).substring(2), 16) == 0) {
					continue;
				}
				JtagDevice device = new JtagDevice(deviceMatcher.group(1), deviceMatcher.group(3), deviceMatcher.group(2), false);
				cable.addDevice(device);
			}
		}
		
		return jtagCableDevices;
	}
	
	public static void testConnection(String host, String port) {
		Job job = new Job(String.format("%s executing...", "Test Connection")) {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				logger.info("Test Connection...");
				String result = ProcLauncherUtils.testConnection(host, port);
				Display.getDefault().asyncExec(new Runnable() {
					@Override
					public void run() {
						if (result.contains("Failed to connect")) {
							UIUtils.showMessageDialog("Test Connection", "Failed to connect to remote target!", MessageDialog.ERROR);
						} else if (result.contains("Succeed to connected")) {
							UIUtils.showMessageDialog("Test Connection", "Succeed to connect to remote target!", MessageDialog.NONE);
						}
					}
				});
				logger.info("Test Connection done.");
				return Status.OK_STATUS;
			}
		};
		job.setUser(true);
		job.schedule();
	}
	
	public static String killExecute(String exe) {
		return ProcLauncherUtils.killExecute(exe);
	}
}
